/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.mocamorena.persistence.dao.impl;

import br.com.mocamorena.exception.PersistenciaException;
import br.com.mocamorena.model.Usuario;
import br.com.mocamorena.persistence.GerenciadorDeConexao;
import br.com.mocamorena.persistence.dao.UsuarioDao;
import br.com.mocamorena.view.DisplayFilter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Diego
 */
public class UsuarioDaoImpl implements UsuarioDao {

    private Connection conn;
    private PreparedStatement pr;
    private ResultSet rs;

    @Override
    public boolean inserir(Usuario usuario) throws PersistenciaException {
        if (usuario == null) {
            throw new PersistenciaException("Não foi informado o usuário a cadastrar.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("INSERT INTO USUARIO(ID, BLOQUEADO, NOME, LOGIN, SENHA, SHADOW) VALUES(NULL, FALSE, ?, ?, ?, FALSE);",
                    Statement.RETURN_GENERATED_KEYS);
            pr.setString(1, usuario.getNome());
            pr.setString(2, usuario.getLogin());
            pr.setString(3, usuario.getSenha());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
                rs = pr.getGeneratedKeys();
                rs.first();
                long id = rs.getLong(1);
                usuario.setId(id);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível cadastrar o usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return sucesso;
    }

    @Override
    public boolean atualizar(Usuario usuario) throws PersistenciaException {
        if (usuario == null) {
            throw new PersistenciaException("Não foi informado o usuário a atualizar.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE USUARIO SET BLOQUEADO=?, NOME=?, LOGIN=? WHERE ID=?;");
            pr.setBoolean(1, usuario.isBloqueado());
            pr.setString(2, usuario.getNome());
            pr.setString(3, usuario.getLogin());
            pr.setLong(4, usuario.getId());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível atualizar o usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }

    @Override
    public boolean excluir(Usuario usuario) throws PersistenciaException {
        if (usuario == null) {
            throw new PersistenciaException("Não foi informado o usuário a excluir.");
        }
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE USUARIO SET SHADOW=TRUE WHERE ID=?;");
            pr.setLong(1, usuario.getId());
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível excluir o usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }

    @Override
    public List<Usuario> listarTodos() throws PersistenciaException {
        List<Usuario> lista = new ArrayList<Usuario>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT ID, BLOQUEADO, NOME, LOGIN, SENHA FROM USUARIO WHERE SHADOW=FALSE ORDER BY ID DESC");
            rs = pr.executeQuery();
            while (rs.next()) {
                Usuario usuario = this.criarUsuario(rs);
                lista.add(usuario);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os usuários.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }

    @Override
    public List<Usuario> listarPeloNome(String nome, DisplayFilter displayFilter) throws PersistenciaException {
        List<Usuario> lista = new ArrayList<Usuario>();
        try {
            conn = GerenciadorDeConexao.abreConexao();
            if (displayFilter != DisplayFilter.TODOS) {
                pr = conn.prepareStatement("SELECT ID, BLOQUEADO, NOME, LOGIN, SENHA FROM USUARIO WHERE SHADOW=FALSE AND NOME LIKE ? AND BLOQUEADO=? ORDER BY NOME");
                pr.setBoolean(2, displayFilter.getValue());
            } else {
                pr = conn.prepareStatement("SELECT ID, BLOQUEADO, NOME, LOGIN, SENHA FROM USUARIO WHERE SHADOW=FALSE AND NOME LIKE ? ORDER BY NOME");
            }
            pr.setString(1, "%" + nome + "%");
            rs = pr.executeQuery();
            while (rs.next()) {
                Usuario usuario = this.criarUsuario(rs);
                lista.add(usuario);
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível listar os usuários.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }
        return lista;
    }

    private Usuario criarUsuario(ResultSet rs) throws PersistenciaException {
        Usuario usuario = null;
        try {
            usuario = new Usuario(rs.getLong("ID"));
            usuario.setBloqueado(rs.getBoolean("BLOQUEADO"));
            usuario.setNome(rs.getString("NOME"));
            usuario.setLogin(rs.getString("LOGIN"));
            usuario.setSenha(rs.getString("SENHA"));
        } catch (SQLException sqlex) {
            StringBuilder msg = new StringBuilder("Não foi possível obter os dados do usuário.");
            msg.append("\nMotivo: ").append(sqlex.getMessage());
            throw new PersistenciaException(msg.toString());
        }
        return usuario;
    }

    @Override
    public boolean isLoginInUse(String login) throws PersistenciaException {
        boolean inUse = false;

        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT ID FROM USUARIO WHERE SHADOW=FALSE AND LOGIN=? LIMIT 0,1");
            pr.setString(1, login);
            rs = pr.executeQuery();
            if (rs.first()) {
                if (rs.getLong("ID") > 0) {
                    inUse = true;
                }
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível verificar se o login está em uso.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }

        return inUse;
    }

    @Override
    public boolean trocarSenha(long id, String novaSenha) throws PersistenciaException {
        boolean sucesso = false;
        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("UPDATE USUARIO SET SENHA=? WHERE ID=?;");
            pr.setString(1, novaSenha);
            pr.setLong(2, id);
            int linhas = pr.executeUpdate();
            if (linhas > 0) {
                sucesso = true;
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível trocar a senha do usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr);
        }
        return sucesso;
    }

    @Override
    public Usuario authenticateUser(String login, String password) throws PersistenciaException {
        Usuario user = null;

        try {
            conn = GerenciadorDeConexao.abreConexao();
            pr = conn.prepareStatement("SELECT ID, BLOQUEADO, NOME, LOGIN, SENHA FROM USUARIO WHERE SHADOW=FALSE AND BLOQUEADO=FALSE AND LOGIN=?");
            pr.setString(1, login);
            rs = pr.executeQuery();
            while (rs.next()) {
                String correctPassword = rs.getString("SENHA");
                if(correctPassword.trim().equals(password.trim())) {
                    user = this.criarUsuario(rs);
                }
            }
        } catch (SQLException exc) {
            StringBuilder msg = new StringBuilder("Não foi possível autenticar o usuário.");
            msg.append("\nMotivo: ").append(exc.getMessage());
            throw new PersistenciaException(msg.toString());
        } finally {
            GerenciadorDeConexao.fechaConexao(conn, pr, rs);
        }

        return user;
    }
}
